package socketmvc.spring.support.driver;

import org.springframework.beans.factory.annotation.AnnotatedBeanDefinition;
import org.springframework.beans.factory.config.BeanDefinition;
import org.springframework.beans.factory.support.AbstractBeanDefinition;
import org.springframework.beans.factory.support.BeanDefinitionRegistry;
import org.springframework.beans.factory.support.GenericBeanDefinition;
import org.springframework.context.annotation.AnnotationBeanNameGenerator;
import org.springframework.context.annotation.ClassPathScanningCandidateComponentProvider;
import org.springframework.core.env.Environment;
import org.springframework.core.io.ResourceLoader;
import org.springframework.core.type.filter.AnnotationTypeFilter;
import socketmvc.core.processor.annotation.SocketControl;
import java.util.HashSet;
import java.util.Set;

public class SocketMvcProcessorBeanDefinitionScanner {

    protected Set<GenericBeanDefinition> beanDefinitionHolders;

    protected Environment environment;

    protected ResourceLoader resourceLoader;

    protected BeanDefinitionRegistry registry;

    protected ClassPathScanningCandidateComponentProvider scanner;

    public SocketMvcProcessorBeanDefinitionScanner(BeanDefinitionRegistry registry,Environment environment,ResourceLoader resourceLoader) {
        this.environment = environment;
        this.registry = registry;
        this.resourceLoader = resourceLoader;
        this.scanner = getScanner();
        this.scanner.setResourceLoader(this.resourceLoader);
        this.beanDefinitionHolders = new HashSet<>();
    }

    public Set<GenericBeanDefinition> getBeanDefinitionHolders() {
        return beanDefinitionHolders;
    }

    public void scan(String... basePackages){
        // 设置扫描器scanner扫描的过滤条件
        AnnotationTypeFilter annotationTypeFilter = new AnnotationTypeFilter(SocketControl.class);
        scanner.addIncludeFilter(annotationTypeFilter);
        //scanner.setBeanNameGenerator(new AnnotationBeanNameGenerator());
        // 遍历每一个basePackages
        for (String basePackage : basePackages) {
            // 通过scanner获取basePackage下的候选类(有标@SimpleRpcClient注解的类)
            Set<BeanDefinition> candidateComponents = scanner.findCandidateComponents(basePackage);
            // 遍历每一个候选类，如果符合条件就把他们注册到容器
            for (BeanDefinition candidateComponent : candidateComponents) {
                if (candidateComponent instanceof AnnotatedBeanDefinition) {

                    // verify annotated class is an interface
                    AnnotatedBeanDefinition definition = (AnnotatedBeanDefinition) candidateComponent;
                    String beanClassName = definition.getBeanClassName();
                    Class<?> beanClass = null;
                    try {
                        beanClass = Class.forName(beanClassName, false, this.getClass().getClassLoader());
                        GenericBeanDefinition beanDefinition = new GenericBeanDefinition();
                        beanDefinition.setBeanClass(beanClass);
                        beanDefinition.setLazyInit(false);
                        beanDefinition.setAutowireMode(AbstractBeanDefinition.AUTOWIRE_BY_TYPE);
                        registry.registerBeanDefinition(beanClass.getSimpleName(),beanDefinition);
                        beanDefinitionHolders.add(beanDefinition);
                    } catch (ClassNotFoundException e) {
                        throw new RuntimeException(e);
                    }
                }
            }
        }
    }

    /**
     * 创建扫描器
     */
    protected ClassPathScanningCandidateComponentProvider getScanner() {
        return new ClassPathScanningCandidateComponentProvider(false, environment) {
            @Override
            protected boolean isCandidateComponent(AnnotatedBeanDefinition beanDefinition) {
                boolean isCandidate = false;
                if (beanDefinition.getMetadata().isIndependent()) {
                    if (!beanDefinition.getMetadata().isAnnotation()) {
                        isCandidate = true;
                    }
                }
                return isCandidate;
            }
        };
    }

}
